/*
 * Title: 	  TRS 身份服务器
 * Copyright: Copyright (c) 2004-2019, TRS信息技术股份有限公司. All rights reserved.
 * License:   see the license file.
 * Company:   TRS信息技术股份有限公司(www.trs.com.cn)
 *
 * Created: guo.jiahua@2019年4月15日 下午6:08:18
 */
package com.gaojinqi.base.core.jpa.enums;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.gaojinqi.base.common.util.StringUtil;
import lombok.AllArgsConstructor;
import lombok.Getter;

import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.Path;
import javax.persistence.criteria.Predicate;
import java.util.Collection;
import java.util.Date;

/**
 * 属性查询符号 <BR>
 *
 * @author gaojinqi
 * @version 1.0
 * @since 2020年04月10日
 */
@Getter
@AllArgsConstructor
public enum PropertyOperatorEnum {

    /**
     * 等于
     */
    EQUAL("=") {
        @Override
        public <T> Predicate getPredicate(Path<T> path, CriteriaBuilder criteriaBuilder, Object value1, Object value2) {
            return criteriaBuilder.equal(path, value1);
        }
    },
    /**
     * 不等于
     */
    NOT_EQUAL("!=") {
        @Override
        public <T> Predicate getPredicate(Path<T> path, CriteriaBuilder criteriaBuilder, Object value1, Object value2) {
            return criteriaBuilder.notEqual(path, value1);
        }
    },
    /**
     * 大于
     */
    GREATER_THAN(">") {
        @Override
        public <T> Predicate getPredicate(Path<T> path, CriteriaBuilder criteriaBuilder, Object value1, Object value2) {
            if (value1 instanceof Date) {
                return criteriaBuilder.greaterThan(path.as(Date.class), (Date) value1);
            }
            if (value1 instanceof Integer) {
                return criteriaBuilder.greaterThan(path.as(Integer.class),
                        (Integer) value1);
            }
            if (value1 instanceof Long) {
                return criteriaBuilder.greaterThan(path.as(Long.class), (Long) value1);
            }
            return null;
        }
    },
    /**
     * 大于等于
     */
    GREATER_THAN_AND_EQUAL(">=") {
        @Override
        public <T> Predicate getPredicate(Path<T> path, CriteriaBuilder criteriaBuilder, Object value1, Object value2) {
            if (value1 instanceof Date) {
                return criteriaBuilder.greaterThanOrEqualTo(path.as(Date.class),
                        (Date) value1);
            }
            if (value1 instanceof Integer) {
                return criteriaBuilder.greaterThanOrEqualTo(path.as(Integer.class),
                        (Integer) value1);
            }
            if (value1 instanceof Long) {
                return criteriaBuilder.greaterThanOrEqualTo(path.as(Long.class),
                        (Long) value1);
            }
            return null;
        }
    },
    /**
     * 小于
     */
    LESS_THAN("<") {
        @Override
        public <T> Predicate getPredicate(Path<T> path, CriteriaBuilder criteriaBuilder, Object value1, Object value2) {
            if (value1 instanceof Date) {
                return criteriaBuilder.lessThan(path.as(Date.class), (Date) value1);
            }
            if (value1 instanceof Integer) {
                return criteriaBuilder.lessThan(path.as(Integer.class), (Integer) value1);
            }
            if (value1 instanceof Long) {
                return criteriaBuilder.lessThan(path.as(Long.class), (Long) value1);
            }
            return null;
        }
    },
    /**
     * 小于等于
     */
    LESS_THAN_AND_EQUAL("<=") {
        @Override
        public <T> Predicate getPredicate(Path<T> path, CriteriaBuilder criteriaBuilder, Object value1, Object value2) {
            if (value1 instanceof Date) {
                return criteriaBuilder.lessThanOrEqualTo(path.as(Date.class),
                        (Date) value1);
            }
            if (value1 instanceof Integer) {
                return criteriaBuilder.lessThanOrEqualTo(path.as(Integer.class),
                        (Integer) value1);
            }
            if (value1 instanceof Long) {
                return criteriaBuilder.lessThanOrEqualTo(path.as(Long.class),
                        (Long) value1);
            }
            return null;
        }
    },
    /**
     * 模糊搜索
     */
    LIKE("LIKE") {
        @Override
        public <T> Predicate getPredicate(Path<T> path, CriteriaBuilder criteriaBuilder, Object value1, Object value2) {
            return criteriaBuilder.like(path.as(String.class), StringUtil.asString(value1));
        }
    },
    /**
     * 模糊搜索
     */
    NOT_LIKE("NOT LIKE") {
        @Override
        public <T> Predicate getPredicate(Path<T> path, CriteriaBuilder criteriaBuilder, Object value1, Object value2) {
            return criteriaBuilder.notLike(path.as(String.class), StringUtil.asString(value1));
        }
    },
    /**
     * 包含
     */
    IN("IN") {
        @Override
        public <T> Predicate getPredicate(Path<T> path, CriteriaBuilder criteriaBuilder, Object value1, Object value2) {
            //判断返回类型是否是集合类型
            boolean isCollection = Collection.class.isAssignableFrom(value1.getClass());
            //判断返回类型是否是数组类型
            boolean isArray = value1.getClass().isArray();
            if (isCollection || isArray) {
                Collection values = (Collection) value1;
                CriteriaBuilder.In in = criteriaBuilder.in(path);
                for (Object value : values) {
                    in.value(value);
                }
                return in;
            }
            // 如果不是集合则直接使用 =
            return criteriaBuilder.equal(path, value1);
        }
    },
    /**
     * 不包含
     */
    NOT_IN("NOT IN") {
        @Override
        public <T> Predicate getPredicate(Path<T> path, CriteriaBuilder criteriaBuilder, Object value1, Object value2) {
            //判断返回类型是否是集合类型
            boolean isCollection = Collection.class.isAssignableFrom(value1.getClass());
            //判断返回类型是否是数组类型
            boolean isArray = value1.getClass().isArray();
            if (isCollection || isArray) {
                Collection values = (Collection) value1;
                CriteriaBuilder.In in = criteriaBuilder.in(path);
                for (Object value : values) {
                    in.value(value);
                }
                return in.not();
            }
            // 如果不是集合则直接使用 =
            return criteriaBuilder.notEqual(path, value1);
        }
    },
    /**
     * 为空
     */
    IS_NULL("IS NULL") {
        @Override
        public <T> Predicate getPredicate(Path<T> path, CriteriaBuilder criteriaBuilder, Object value1, Object value2) {
            return criteriaBuilder.isNull(path);
        }
    },
    /**
     * 不为空
     */
    IS_NOT_NULL("IS NOT NULL") {
        @Override
        public <T> Predicate getPredicate(Path<T> path, CriteriaBuilder criteriaBuilder, Object value1, Object value2) {
            return criteriaBuilder.isNotNull(path);
        }
    },
    /**
     * 存在
     */
    EXISTS("EXISTS") {
        @Override
        public <T> Predicate getPredicate(Path<T> path, CriteriaBuilder criteriaBuilder, Object value1, Object value2) {
            // 暂不支持
            return null;
        }
    },
    /**
     * ...之间
     */
    BETWEEN("BETWEEN") {
        @Override
        public <T> Predicate getPredicate(Path<T> path, CriteriaBuilder criteriaBuilder, Object value1, Object value2) {
            if (value1 instanceof Date) {
                return criteriaBuilder.between(path.as(Date.class), (Date) value1,
                        (Date) value2);
            }
            if (value1 instanceof Integer) {
                return criteriaBuilder.between(path.as(Integer.class), (Integer) value1,
                        (Integer) value2);
            }
            if (value1 instanceof Long) {
                return criteriaBuilder.between(path.as(Long.class), (Long) value1,
                        (Long) value2);
            }
            return null;
        }
    },
    /**
     * 不存在
     */
    NOT_EXISTS("NOT EXISTS") {
        @Override
        public <T> Predicate getPredicate(Path<T> path, CriteriaBuilder criteriaBuilder, Object value1, Object value2) {
            // 暂不支持
            return null;
        }
    },
    ;

    private final String op;

    public abstract <T> Predicate getPredicate(Path<T> path, CriteriaBuilder criteriaBuilder, Object value1, Object value2);

}
